package com.yygo.webapp.controller.attachment;

import com.yygo.Constants;
import com.yygo.configentity.attachment.RoleAttachment;
import com.yygo.model.*;
import com.yygo.model.enums.AttachmentType;
import com.yygo.service.LoanRequestManager;
import com.yygo.service.RoleAttachmentsConfigurer;
import com.yygo.service.UserManager;
import com.yygo.util.ZipUtil;
import com.yygo.webapp.controller.BaseFormController;
import com.yygo.webapp.controller.FileUpload;
import org.apache.commons.io.FileUtils;
import org.appfuse.service.GenericManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.mail.internet.MimeUtility;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Controller
@RequestMapping("/attachments")
public class AttachmentController extends BaseFormController {
    private LoanRequestManager loanRequestManager;

    private GenericManager<Attachment, Long> attachmentManager = null;

    @Autowired
    public void setAttachmentManager(@Qualifier("attachmentManager") GenericManager<Attachment, Long> attachmentManager) {
        this.attachmentManager = attachmentManager;
    }

    @Autowired
    public void setLoanRequestManager(@Qualifier("loanRequestManager") LoanRequestManager loanRequestManager) {
        this.loanRequestManager = loanRequestManager;
    }

    @Autowired
    private UserManager userManager;

    @Autowired
    private RoleAttachmentsConfigurer roleAttachmentsConfigurer;

    @RequestMapping(method = RequestMethod.GET)
    public Model handleRequest(@RequestParam(required = true, value = "reqId") Long reqId, HttpServletRequest request)
            throws Exception {
        Model model = new ExtendedModelMap();
        LoanRequest loanRequest = loanRequestManager.getLoanRequest(reqId);

        if (request.isUserInRole(Constants.DEALER_USER_ROLE)) {
            List<Attachment> attachments = new ArrayList<Attachment>();
            for (Attachment attachment : loanRequest.getAttachmentList()) {
                if (attachment.getType().equals(AttachmentType.Credit) || attachment.getType().equals(AttachmentType.Request_Audit) || attachment.getType().equals(AttachmentType.Loan_Audit))
                    attachments.add(attachment);
            }
            loanRequest.getAttachmentList().clear();
            loanRequest.getAttachmentList().addAll(attachments);
        }
        List<Attachment> attachments = new ArrayList<Attachment>();
        for (Attachment attachment : loanRequest.getAttachmentList()) {
            if (!(attachment.getType().equals(AttachmentType.BusinessForm) || attachment.getType().equals(AttachmentType.AuditResult) || attachment.getType().equals(AttachmentType.InsuranceForm)))
                attachments.add(attachment);
        }
        loanRequest.getAttachmentList().clear();
        loanRequest.getAttachmentList().addAll(attachments);

        model.addAttribute(loanRequest);
        return model;
    }

    @ModelAttribute
    protected FileUpload showForm(HttpServletRequest request)
            throws Exception {
        return new FileUpload();
    }

    //@ModelAttribute
    protected LoanRequest getLoanRequest(FileUpload fileUpload, HttpServletRequest request)
            throws Exception {
        if (fileUpload != null && fileUpload.getReqId() != null) {
            LoanRequest loanRequest = loanRequestManager.getLoanRequest(fileUpload.getReqId());
            if (request.isUserInRole(Constants.DEALER_USER_ROLE)) {
                List<Attachment> attachments = new ArrayList<Attachment>();
                for (Attachment attachment : loanRequest.getAttachmentList()) {
                    if (attachment.getType().equals(AttachmentType.Credit) || attachment.getType().equals(AttachmentType.Request_Audit) || attachment.getType().equals(AttachmentType.Loan_Audit))
                        attachments.add(attachment);
                }
                loanRequest.getAttachmentList().clear();
                loanRequest.getAttachmentList().addAll(attachments);
            }
            return loanRequest;
        }
        return null;
    }

    @RequestMapping(method = RequestMethod.POST)
    public String onSubmit(FileUpload fileUpload, BindingResult errors, HttpServletRequest request, Principal principal)
            throws Exception {

        if (validator != null) { // validator is null during testing
            validator.validate(fileUpload, errors);
            if (errors.hasErrors()) {
                return "attachments";
            }
        }

        // validate a file was entered
        if (fileUpload.getFile().length == 0) {
            Object[] args =
                    new Object[]{getText("uploadForm.file", request.getLocale())};
            errors.rejectValue("file", "errors.required", args, "File");
            return "attachments";
        }

        LoanRequest loanRequest = loanRequestManager.get(fileUpload.getReqId());
        User loginUser = userManager.getUserByUsername(principal.getName());

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        CommonsMultipartFile file = (CommonsMultipartFile) multipartRequest.getFile("file");

        // the directory to upload to
        String name = fileUpload.getName();
        String uploadDir = getUploadPath();
        uploadDir += File.separator + loanRequest.getNumber() + File.separator + name;

        // Create the directory if it doesn't exist
        File dirPath = new File(uploadDir);

        if (!dirPath.exists()) {
            dirPath.mkdirs();
        }

        //retrieve the file data
        InputStream stream = file.getInputStream();

        //write the file to the file specified
        OutputStream bos = new FileOutputStream(uploadDir + File.separator + file.getOriginalFilename());
        int bytesRead;
        byte[] buffer = new byte[8192];

        while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {
            bos.write(buffer, 0, bytesRead);
        }

        bos.close();

        //close the stream
        stream.close();

        AttachmentType attachmentType = null;
        RoleAttachment roleAttachment = getAttachmentInfo(loanRequest, loginUser);
        if (roleAttachment != null) {
            attachmentType = AttachmentType.valueOf(roleAttachment.getType());
        }


        Attachment attachment = new Attachment();
        attachment.setLoanRequest(loanRequest);
        attachment.setName(name);
        attachment.setType(attachmentType);
        attachment.setTime(new Date());
        attachment.setFileName(file.getOriginalFilename());
        attachment.setOperator(request.getRemoteUser());

        attachmentManager.save(attachment);

        return "redirect:/attachments?reqId=" + fileUpload.getReqId();
    }

    @RequestMapping(value="/{number}/{name}/{attachmentId}", method = RequestMethod.GET)
    public void getImage(@PathVariable String number, @PathVariable String name, @PathVariable Long attachmentId, HttpServletResponse response) throws UnsupportedEncodingException {
        Attachment attachment = attachmentManager.get(attachmentId);
        String fileName = attachment.getFileName();
        String uploadDir = getUploadPath();
        uploadDir += File.separator + number + File.separator + name;
        FileInputStream fis = null;
        if (fileName.toLowerCase().endsWith("png"))
            response.setContentType(MediaType.IMAGE_PNG_VALUE);
        else if (fileName.toLowerCase().endsWith("gif"))
            response.setContentType(MediaType.IMAGE_GIF_VALUE);
        else if (fileName.toLowerCase().endsWith("jpeg"))
            response.setContentType(MediaType.IMAGE_JPEG_VALUE);
        else if (fileName.toLowerCase().endsWith("xls") || fileName.toLowerCase().endsWith("doc")){
            response.setHeader("Content-Disposition", "attachment; filename=".concat(MimeUtility.encodeWord(fileName)));
            response.setContentType("application/octet-stream; charset=utf-8");
        }


        try {
            OutputStream out = response.getOutputStream();
            File file = new File(uploadDir + File.separator + fileName);
            fis = new FileInputStream(file);
            byte[] b = new byte[fis.available()];
            fis.read(b);
            out.write(b);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @RequestMapping(value="/download/{id}", method = RequestMethod.GET)
    public String downloadAttachments(@PathVariable Long id, HttpServletResponse response) {
        LoanRequest loanRequest = loanRequestManager.loadWholeLoanRequest(id);
        List<Attachment> attachments = loanRequest.getAttachmentList();

        String uploadDir = getUploadPath();
        File[] files = new File[attachments.size()];
        int i = 0;
        for (Attachment attachment : attachments) {
            files[i++] = new File(uploadDir + File.separator + loanRequest.getNumber()  + File.separator + attachment.getName());
        }

        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");
        response.setHeader("Content-Disposition", "attachment;fileName="
                + loanRequest.getNumber() + ".zip");
        try {
            OutputStream out = response.getOutputStream();
            ZipUtil.zip(uploadDir + File.separator + loanRequest.getNumber(), out);
            out.flush();
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {

        }
        return null;
    }

    private String getUploadPath() {
        // the directory to upload to
        String uploadDir = getServletContext().getRealPath("/resources");

        // The following seems to happen when running jetty:run
        if (uploadDir == null) {
            uploadDir = new File("src/main/webapp/resources").getAbsolutePath();
        }
        //uploadDir += "/" + number + "/";
        return uploadDir;
    }

    @ModelAttribute("availableTypes")
    protected List<LabelValue> getAvailableTypes(@RequestParam(required = false, value = "reqId") Long reqId, HttpServletRequest request, Principal principal) {
        if(reqId != null){
            LoanRequest loanRequest = loanRequestManager.get(reqId);
            User loginUser = userManager.getUserByUsername(principal.getName());

            RoleAttachment roleAttachment = getAttachmentInfo(loanRequest, loginUser);
            if (roleAttachment != null) {
                String attachmentKey = roleAttachment.getAttachmentKey();
                return getList(attachmentKey);
            }
        }

        return null;
    }

    private RoleAttachment getAttachmentInfo(LoanRequest loanRequest, User loginUser) {
        for (Role role : loginUser.getRoles()) {
            RoleAttachment roleAttachment = roleAttachmentsConfigurer.getPhase(role.getName(), loanRequest.getPhase().toString(), loanRequest.getStatus().toString());
            if (roleAttachment != null) {
                return roleAttachment;
            }
        }
        return null;
    }

}
